#pragma region Licensing
/*
       LOGL::GLib -> LorgonJortle's OpenGL Game Library
       Copyright (C) 2011  Jesse 'LorgonJortle' Wilkerson

       This program is free software: you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation, either version 3 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#pragma endregion

#include "Vector2.h"

namespace LOGL_GLib
{
     namespace Common
     {

          /******************************************************************************
           Vector2::Vector2();
                    Arguments:
                         void

                    Description:
                         Constructs a Vector2 with both components set to zero.

                    Returns:
                         The Vector2 object.
          *******************************************************************************/
          Vector2::Vector2()
          {
               X = 0.0f;
               Y = 0.0f;
          }

          /******************************************************************************
           Vector2::Vector2(GLfloat _XY);
                    Arguments:
                         GLfloat _XY:
                              The value to set both X and Y to.

                    Description:
                         Constructs a Vector2 with the specified value for X and Y.

                    Returns:
                         The Vector2 object.
          *******************************************************************************/
          Vector2::Vector2(GLfloat _XY)
          {
               X = _XY;
               Y = _XY;
          }

          /******************************************************************************
           Vector2::Vector2(GLfloat _X, GLfloat _Y);
                    Arguments:
                         GLfloat _X:
                              The value to set X to.
                         GLfloat _Y:
                              The value to set Y to.

                    Description:
                         Constructs a Vector2 with the specified values.

                    Returns:
                         The Vector2 object.
          *******************************************************************************/
          Vector2::Vector2(GLfloat _X, GLfloat _Y)
          {
               X = _X;
               Y = _Y;
          }

          /******************************************************************************
           GLboolean Vector2::operator==(const Vector2& _Vector) const;
                    Arguments:
                         const Vector2& _Vector;
                              The vector to compare against.

                    Description:
                         Determines if the specified vector is equal to this.

                    Returns:
                         Whether or not the two vectors are equal.
          *******************************************************************************/
          GLboolean Vector2::operator==(const Vector2& _Vector) const
          {
               if(Equal(X, _Vector.X) && Equal(Y, _Vector.Y))
                    return GL_TRUE;
               else
                    return GL_FALSE;
          }

          /******************************************************************************
           GLboolean Vector2::operator!=(const Vector2& _Vector) const;
                    Arguments:
                         const Vector2& _Vector;
                              The vector to compare against.

                    Description:
                         Determines if the specified vector is not equal to this.

                    Returns:
                         Whether or not the two vectors are not equal.
          *******************************************************************************/
          GLboolean Vector2::operator!=(const Vector2& _Vector) const
          {
               return !(*this == _Vector);
          }

          /******************************************************************************
           Vector2& Vector2::operator=(const Vector2& _Vector);
                    Arguments:
                         const Vector2& _Vector;
                              The vector to assign to this.

                    Description:
                         Assigns the specified vector to this.

                    Returns:
                         A reference to this, for daisy chaining.
          *******************************************************************************/
          Vector2& Vector2::operator=(const Vector2& _Vector)
          {
               X = _Vector.X;
               Y = _Vector.Y;

               return *this;
          }

          /******************************************************************************
           Vector2& Vector2::operator=(GLfloat _XY);
                    Arguments:
                         GLfloat _XY:
                              The value to assign each component.

                    Description:
                         Assigns the specified value to all components of this.

                    Returns:
                         A reference to this, for daisy chaining.
          *******************************************************************************/
          Vector2& Vector2::operator=(GLfloat _XY)
          {
               X = _XY;
               Y = _XY;

               return *this;
          }

          /******************************************************************************
           Vector2 Vector2::operator-() const;
                    Arguments:
                         void

                    Description:
                         Computes the negated version of this.

                    Returns:
                         The negated version of this.
          *******************************************************************************/
          Vector2 Vector2::operator-() const
          {
               return Vector2(-X, -Y);
          }

          /******************************************************************************
           Vector2 Vector2::operator +(const Vector2& _Delta) const;
                    Arguments:
                         const Vector2& _Delta:
                              The vector to add to another.

                    Description:
                         Computes the sum of two vectors.

                    Returns:
                         The resultant vector.
          *******************************************************************************/
          Vector2 Vector2::operator +(const Vector2& _Delta) const
          {
               Vector2 resultant;

               resultant.X = X + _Delta.X;
               resultant.Y = Y + _Delta.Y;

               return resultant;
          }

          /******************************************************************************
           GLvoid Vector2::operator +=(const Vector2& _Delta);
                    Arguments:
                         const Vector2& _Delta:
                              The vector to add to this.

                    Description:
                         Adds the specified vector to this.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::operator +=(const Vector2& _Delta)
          {
               X += _Delta.X;
               Y += _Delta.Y;
          }

          /******************************************************************************
           Vector2 Vector2::operator -(const Vector2& _Delta) const;
                    Arguments:
                         const Vector2& _Delta:
                              The vector to subtract from another.

                    Description:
                         Computes the difference of two vectors.

                    Returns:
                         The resulting difference vector.
          *******************************************************************************/
          Vector2 Vector2::operator -(const Vector2& _Delta) const
          {
               Vector2 resultant;

               resultant.X = X - _Delta.X;
               resultant.Y = Y - _Delta.Y;

               return resultant;
          }

          /******************************************************************************
           GLvoid Vector2::operator -=(const Vector2& _Delta);
                    Arguments:
                         const Vector2& _Delta:
                              The vector to subtract from this.

                    Description:
                         Subtracts the specified vector from this.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::operator -=(const Vector2& _Delta)
          {
               X -= _Delta.X;
               Y -= _Delta.Y;
          }

          /******************************************************************************
           Vector2 Vector2::operator *(GLfloat _Scale) const;
                    Arguments:
                         GLfloat _Scale:
                              The scalar to multiply the vector by.

                    Description:
                         Computes the scaled resultant of a vector and scalar.

                    Returns:
                         The resulting scaled vector.
          *******************************************************************************/
          Vector2 Vector2::operator *(GLfloat _Scale) const
          {
               Vector2 resultant;

               resultant.X = X * _Scale;
               resultant.Y = Y * _Scale;

               return resultant;
          }

          /******************************************************************************
           GLvoid Vector2::operator *=(GLfloat _Scale);
                    Arguments:
                         GLfloat _Scale:
                              The scalar to multiply this by.

                    Description:
                         Scales this by the specified scalar.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::operator *=(GLfloat _Scale)
          {
               X *= _Scale;
               Y *= _Scale;
          }

          /******************************************************************************
           Vector2 Vector2::operator /(GLfloat _Divisor) const;
                    Arguments:
                         GLfloat _Divisor:
                              The scalar to divide the vector by.

                    Description:
                         Computes the resultant of this dived by the specified scalar.

                    Returns:
                         The resulting vector.
          *******************************************************************************/
          Vector2 Vector2::operator/(GLfloat _Divisor) const
          {
               Vector2 resultant;

               resultant.X = X / _Divisor;
               resultant.Y = Y / _Divisor;

               return resultant;
          }

          /******************************************************************************
           GLvoid Vector2::operator /=(GLfloat _Divisor) const;
                    Arguments:
                         GLfloat _Divisor:
                              The scalar to divide the vector by.

                    Description:
                         Divides this by the specified scalar.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::operator/=(GLfloat _Divisor)
          {
               X /= _Divisor;
               Y /= _Divisor;
          }

          /******************************************************************************
           std::ostream& Vector2::operator <<(std::ostream& _Stream,
                                              const Vector2& _Vector);
                    Arguments:
                         std::ostream& _Stream:
                              The ouput stream to write to.
                         const Vector2& _Vector:
                              The vector to write to the stream.

                    Description:
                         Outputs the specifed vector to standard out.

                    Returns:
                         A reference to the stream for daisy-chaining.
          *******************************************************************************/
          std::ostream& operator<<(std::ostream& _Stream, const Vector2& _Vector)
          {
               _Stream << _Vector.ToString();

               return _Stream;
          }

          /******************************************************************************
           GLvoid Vector2::Negate();
                    Arguments:
                         void

                    Description:
                         Negates all components of this.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::Negate()
          {
               X *= -1;
               Y *= -1;
          }

          /******************************************************************************
           static Vector2 Vector2::Negate(const Vector2& _Vector);
                    Arguments:
                         const Vecctor2& _Vector:
                              The vector to negate.

                    Description:
                         Negates all components of the specified vector.

                    Returns:
                         The negated vector.
          *******************************************************************************/
          Vector2 Vector2::Negate(const Vector2& _Vector)
          {
               return Vector2(_Vector.X * -1.0f, _Vector.Y * -1.0f);
          }

          /******************************************************************************
           GLfloat Vector2::Length();
                    Arguments:
                         void

                    Description:
                         Calculates the length of the vector.

                    Returns:
                         The length of the vector.
          *******************************************************************************/
          GLfloat Vector2::Length() const
          {
               return (GLfloat)sqrt((X * X) + (Y * Y));
          }

          /******************************************************************************
           GLvoid Vector2::Normalize();
                    Arguments:
                         void

                    Description:
                         Calculates the appropriate unit vector.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Vector2::Normalize()
          {
               GLfloat length = Length();

               /* Avoid division by 0. */
               if(Equal(length, 0.0f))
                    length = 1.0f;

               X /= length;
               Y /= length;
          }

          /******************************************************************************
           static Vector2 Vector2::Normalize(const Vector2& _Vector);
                    Arguments:
                         const Vector2& _Vector:
                              The vector to return the normal of.

                    Description:
                         Calculates the appropriate unit vector for the specified vector.

                    Returns:
                         The appropriate unit vector for the specified vector.
          *******************************************************************************/
          Vector2 Vector2::Normalize(const Vector2& _Vector)
          {
               GLfloat length = _Vector.Length();

               /* Avoid division by zero. */
               if(Equal(length, 0.0f))
                    length = 1.0f;

               Vector2 norm = _Vector;

               norm.X /= length;
               norm.Y /= length;

               return norm;
          }

          /******************************************************************************
           GLfloat Vector2::Dot(const Vector2& _B) const;
                    Arguments:
                         const Vector2& _B:
                              The vector to calculate the dot product against.

                    Description:
                         Calculates the dot product between this and the specified vector.

                    Returns:
                         The dot product between this and the specified vector.
          *******************************************************************************/
          GLfloat Vector2::Dot(const Vector2& _B) const
          {
               return (X * _B.X) + (Y * _B.Y);
          }

          /******************************************************************************
           static GLfloat Vector2::Dot(const Vector2& _A, const Vector2& _B);
                    Arguments:
                         const Vector2& _A:
                              The first vector to work with.
                         const Vector2& _B:
                              The second vector to work with.

                    Description:
                         Calculates the dot product between the two specified vectors.

                    Returns:
                         The dot product between the two specified vectors.
          *******************************************************************************/
          GLfloat Vector2::Dot(const Vector2& _A, const Vector2& _B)
          {
               return (_A.X * _B.X) + (_A.Y * _B.Y);
          }

          /******************************************************************************
           GLfloat Vector2::AngleBetween(const Vector2& _B) const;
                    Arguments:
                         const Vector2& _B:
                              The vector to work with.

                    Description:
                         Calculates the angle (in radians) between this and the specified vector.

                    Returns:
                         The angle between this and the specified vector (in radians).
          *******************************************************************************/
          GLfloat Vector2::AngleBetween(const Vector2& _B) const
          {
               /* Calculate a difference vector. */
               Vector2 c = (*this - _B);

               /* Find all magnitudes. */
               GLfloat aLength = Length();
               GLfloat bLength = _B.Length();
               GLfloat cLength = c.Length();

               /* Check to see if this or _B are zero vectors. */
               if(aLength == 0 || bLength == 0)
                    return 0;

               /* If the length of c is zero, the vectors are equal. */
               if(cLength == 0)
                    return 0;

               /* Otherwise, calculate the angle between them. */
               return acosf(((aLength * aLength) + (bLength * bLength) - (cLength * cLength)) / (2 * aLength * bLength));
          }

          /******************************************************************************
           static GLfloat Vector2::AngleBetween(const Vector2& _A, const Vector2& _B);
                    Arguments:
                         const Vector2& _A:
                              The first vector to work with.
                         const Vector2& _B:
                              The second vector to work with.

                    Description:
                         Calculates the angle (in radians) between the two specified vectors.

                    Returns:
                         The angle between the two specified vectors (in radians).
          *******************************************************************************/
          GLfloat Vector2::AngleBetween(const Vector2& _A, const Vector2& _B)
          {
               /* Calculate a difference vector. */
               Vector2 c = (_A - _B);

               /* Find all magnitudes. */
               GLfloat aLength = _A.Length();
               GLfloat bLength = _B.Length();
               GLfloat cLength = c.Length();

               /* Check to see if this or _B are zero vectors. */
               if(aLength == 0 || bLength == 0)
                    return 0;

               /* If the length of c is zero, the vectors are equal. */
               if(cLength == 0)
                    return 0;

               /* Otherwise, calculate the angle between them. */
               return acosf(((aLength * aLength) + (bLength * bLength) - (cLength * cLength)) / (2 * aLength * bLength));
          }

          /******************************************************************************
           GLfloat Vector2::Component(const Vector2& _B) const;
                    Arguments:
                         const Vector2& _B:
                              The vector to work with.

                    Description:
                         Calculates the distance this points in the direction of the specified vector.

                    Returns:
                         The distance this points in the direction of the specified vector.
          *******************************************************************************/
          GLfloat Vector2::Component(const Vector2& _B) const
          {
               if(Equal(Length(), 0.0f) || Equal(_B.Length(), 0.0f))
                    return 0;
               else
                    return Dot(_B) / _B.Length();
          }

          /******************************************************************************
           static GLfloat Vector2::Component(const Vector2& _A, const Vector2& _B);
                    Arguments:
                         const Vector2& _A:
                              The first vector to work with.
                         const Vector2& _B:
                              The second vector to work with.

                    Description:
                         Calculates the distance one vector points in the direction of another.

                    Returns:
                         The distance one vector points in the direction of another.
          *******************************************************************************/
          GLfloat Vector2::Component(const Vector2& _A, const Vector2& _B)
          {
               if(Equal(_A.Length(), 0) || Equal(_B.Length(), 0))
                    return 0;
               else
                    return _A.Dot(_B) / _B.Length();
          }

          /******************************************************************************
           Vector2 Vector2::Project(const Vector2& _B) const;
                    Arguments:
                         const Vector2& _B:
                              The vector to work with.

                    Description:
                         Calculates this projected on the specified vector.

                    Returns:
                         The vector of this projected on the specified vector.
          *******************************************************************************/
          Vector2 Vector2::Project(const Vector2& _B) const
          {
               if(Equal(Length(), 0) || Equal(_B.Length(), 0))
                    return Vector2(0);
               else
               {
                    Vector2 vec = Vector2::Normalize(_B);
                    GLfloat comp = Component(_B);
                    vec *= comp;

                    return vec;
               }
          }

          /******************************************************************************
           static Vector2 Vector2::Project(const Vector2& _A, const Vector2& _B);
                    Arguments:
                         const Vector2& _A:
                              The first vector to work with.
                         const Vector2& _B:
                              The second vector to work with.

                    Description:
                         Calculates one vector projected on another.

                    Returns:
                         The resulting, projected vector.
          *******************************************************************************/
          Vector2 Vector2::Project(const Vector2& _A, const Vector2& _B)
          {
               if(Equal(_A.Length(), 0) || Equal(_B.Length(), 0))
                    return Vector2(0);
               else
               {
                    Vector2 vec = Vector2::Normalize(_B);
                    GLfloat comp = _A.Component(_B);
                    vec *= comp;

                    return vec;
               }
          }

          /******************************************************************************
           Vector2 Vector2::Reflect(const Vector2& _B) const;
                    Arguments:
                         const Vector2& _B:
                              The vector to work with.

                    Description:
                         Calculates the reflection of this across the specified vector.

                    Returns:
                         The reflection vector of this across the specified vector.
          *******************************************************************************/
          Vector2 Vector2::Reflect(const Vector2& _B) const
          {
               if(Equal(Dot(_B), 0.0f))
                    return -(*this);
               else
               {
                    Vector2 vec = Vector2::Normalize(_B);
                    vec *= Dot(vec) * 2.0f;

                    return -(*this - vec);
               }
          }

          /******************************************************************************
           static Vector2 Vector2::Reflect(const Vector2& _A, const Vector2& _B);
                    Arguments:
                         const Vector2& _A:
                              The first vector to work with.
                         const Vector2& _B:
                              The second vector to work with.

                    Description:
                         Calculates the reflection of one vector across another.

                    Returns:
                         The reflection vector of the two specified vectors.
          *******************************************************************************/
          Vector2 Vector2::Reflect(const Vector2& _A, const Vector2& _B)
          {
               if(Equal(_A.Dot(_B), 0.0f))
                    return -_A;
               else
               {
                    Vector2 vec = Vector2::Normalize(_B);
                    vec *= _A.Dot(vec) * 2.0f;

                    return -(_A - vec);
               }
          }

          /******************************************************************************
           std::string Vector2::ToString() const;
                    Arguments:
                         void

                    Description:
                         Returns a string representation of the Vector2.

                    Returns:
                         A string representation of the Vector2.
          *******************************************************************************/
          std::string Vector2::ToString() const
          {
               std::stringstream stream;
               stream << "(" << X << "," << Y << ")";
               return stream.str();
          }

     } /* Namespace Common. */
} /* Namespace LOGL_GLib. */
